/*
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#pragma once

#include <memory>
#include <vector>
#include <functional>
#include <mutex>
#include <unordered_map>

#include "esp_err.h"
#include "driver/i2c_master.h"
#include "driver/gpio.h"

#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"

// 软件I2C类型定义（内置实现）
struct SoftI2CBus {
    gpio_num_t scl_pin;
    gpio_num_t sda_pin;
    uint32_t freq_delay_us;
    bool initialized;
};
typedef SoftI2CBus* soft_i2c_master_bus_t;

/**
 * @brief I2C类型枚举
 */
enum class I2CType {
    HARDWARE = 0,    /*!< 硬件I2C */
    SOFTWARE         /*!< 软件I2C */
};

/**
 * @brief I2C时钟源配置
 */
enum class I2CClockSource {
    DEFAULT = 0,     /*!< 默认时钟源 */
    XTAL,            /*!< 外部晶振 */
    RC_FAST,         /*!< 内部RC振荡器 */
    APB              /*!< APB时钟 */
};

/**
 * @brief I2C速度配置
 */
enum class I2CSpeed : uint32_t {
    SPEED_100K = 100000,   /*!< 标准模式 100kHz */
    SPEED_400K = 400000,   /*!< 快速模式 400kHz */
    SPEED_1M = 1000000     /*!< 快速模式+ 1MHz */
};

/**
 * @brief I2C地址长度
 */
enum class I2CAddrLength {
    ADDR_7BIT = 0,   /*!< 7位地址 */
    ADDR_10BIT       /*!< 10位地址 */
};

/**
 * @brief I2C配置结构体
 */
struct I2CConfig {
    I2CType type = I2CType::HARDWARE;                    /*!< I2C类型 */
    int i2c_port = 0;                                    /*!< I2C端口号 */
    gpio_num_t scl_io_num = GPIO_NUM_NC;                 /*!< SCL引脚 */
    gpio_num_t sda_io_num = GPIO_NUM_NC;                 /*!< SDA引脚 */
    I2CClockSource clk_source = I2CClockSource::DEFAULT; /*!< 时钟源 */
    uint32_t glitch_ignore_cnt = 7;                      /*!< 毛刺过滤计数 */
    bool enable_internal_pullup = true;                  /*!< 启用内部上拉 */
    bool allow_pd = false;                               /*!< 允许掉电 */
    uint8_t intr_priority = 0;                           /*!< 中断优先级 */
    uint32_t trans_queue_depth = 0;                      /*!< 传输队列深度 */
    uint32_t scl_speed_hz = 100000;                      /*!< SCL频率 */
};

/**
 * @brief 统一的ESP32 I2C类
 * 
 * 这个类包含了I2C主机的基本功能，可以直接在其他设备类中使用
 * 支持硬件和软件I2C，提供基础的I2C操作接口
 */
class I2cMaster {
public:
    /**
     * @brief 默认构造函数
     */
    I2cMaster() = default;
    
    /**
     * @brief 析构函数
     */
    ~I2cMaster();
    
    // 禁用拷贝构造和赋值
    I2cMaster(const I2cMaster&) = delete;
    I2cMaster& operator=(const I2cMaster&) = delete;
    
    // 启用移动构造和赋值
    I2cMaster(I2cMaster&& other) noexcept;
    I2cMaster& operator=(I2cMaster&& other) noexcept;
    
    /**
     * @brief 初始化I2C
     * @param config I2C配置
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t init(const I2CConfig& config);
    
    /**
     * @brief 检查是否已初始化
     * @return true: 已初始化, false: 未初始化
     */
    bool isInitialized() const { return initialized_; }
    
    /**
     * @brief 获取I2C类型
     * @return I2C类型
     */
    I2CType getType() const { return type_; }
    
    /**
     * @brief 获取端口号
     * @return 端口号
     */
    int getPort() const { return port_; }
    
    // ==================== 总线管理功能 ====================
    
    /**
     * @brief 探测设备是否存在
     * @param device_address 设备地址
     * @param timeout_ms 超时时间(毫秒)
     * @return true: 设备存在, false: 设备不存在
     */
    bool probeDevice(uint16_t device_address, int timeout_ms = 1000);
    
    /**
     * @brief 扫描总线上的设备
     * @param found_devices 输出找到的设备地址列表
     * @param timeout_ms 每个地址的超时时间
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t scanBus(std::vector<uint8_t>& found_devices, int timeout_ms = 100);
    
    /**
     * @brief 重置I2C总线
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t resetBus();
    
    /**
     * @brief 检查总线是否空闲
     * @return true: 总线空闲, false: 总线忙碌
     */
    bool isBusIdle() const;
    
    // ==================== 设备管理功能 ====================
    
    /**
     * @brief 添加I2C设备（用于性能优化）
     * @param device_address 设备地址
     * @param scl_speed_hz SCL频率，默认100kHz
     * @return 设备句柄，失败返回nullptr
     */
    i2c_master_dev_handle_t addDevice(uint16_t device_address, uint32_t scl_speed_hz = 100000);
    
    /**
     * @brief 移除I2C设备
     * @param dev_handle 设备句柄
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t removeDevice(i2c_master_dev_handle_t dev_handle);
    
    // ==================== 基础传输功能 ====================
    
    /**
     * @brief 发送数据到指定设备
     * @param device_address 设备地址
     * @param data 数据缓冲区
     * @param size 数据大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t transmit(uint16_t device_address, const uint8_t* data, size_t size, int timeout_ms = 1000);
    
    /**
     * @brief 发送数据到指定设备（vector版本）
     * @param device_address 设备地址
     * @param data 数据向量
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t transmit(uint16_t device_address, const std::vector<uint8_t>& data, int timeout_ms = 1000);
    
    /**
     * @brief 使用设备句柄发送数据（性能优化版本）
     * @param dev_handle 设备句柄
     * @param data 数据缓冲区
     * @param size 数据大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t transmit(i2c_master_dev_handle_t dev_handle, const uint8_t* data, size_t size, int timeout_ms = 1000);
    
    /**
     * @brief 从指定设备接收数据
     * @param device_address 设备地址
     * @param buffer 接收缓冲区
     * @param size 接收大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t receive(uint16_t device_address, uint8_t* buffer, size_t size, int timeout_ms = 1000);
    
    /**
     * @brief 从指定设备接收数据（vector版本）
     * @param device_address 设备地址
     * @param data 输出数据向量
     * @param size 接收大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t receive(uint16_t device_address, std::vector<uint8_t>& data, size_t size, int timeout_ms = 1000);
    
    /**
     * @brief 使用设备句柄接收数据（性能优化版本）
     * @param dev_handle 设备句柄
     * @param buffer 接收缓冲区
     * @param size 接收大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t receive(i2c_master_dev_handle_t dev_handle, uint8_t* buffer, size_t size, int timeout_ms = 1000);
    
    /**
     * @brief 发送后接收数据
     * @param device_address 设备地址
     * @param write_data 写数据缓冲区
     * @param write_size 写数据大小
     * @param read_buffer 读缓冲区
     * @param read_size 读数据大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t transmitReceive(uint16_t device_address, const uint8_t* write_data, size_t write_size,
                              uint8_t* read_buffer, size_t read_size, int timeout_ms = 1000);
    
    /**
     * @brief 发送后接收数据（vector版本）
     * @param device_address 设备地址
     * @param write_data 写数据向量
     * @param read_data 读数据向量
     * @param read_size 读数据大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t transmitReceive(uint16_t device_address, const std::vector<uint8_t>& write_data,
                              std::vector<uint8_t>& read_data, size_t read_size, int timeout_ms = 1000);
    
    /**
     * @brief 使用设备句柄发送后接收数据（性能优化版本）
     * @param dev_handle 设备句柄
     * @param write_data 写数据缓冲区
     * @param write_size 写数据大小
     * @param read_buffer 读缓冲区
     * @param read_size 读数据大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t transmitReceive(i2c_master_dev_handle_t dev_handle, const uint8_t* write_data, size_t write_size,
                              uint8_t* read_buffer, size_t read_size, int timeout_ms = 1000);
    
    // ==================== 寄存器操作功能 ====================
    
    /**
     * @brief 写寄存器（单字节）
     * @param device_address 设备地址
     * @param reg_addr 寄存器地址
     * @param data 数据
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t writeRegister(uint16_t device_address, uint8_t reg_addr, uint8_t data, int timeout_ms = 1000);
    
    /**
     * @brief 写寄存器（多字节）
     * @param device_address 设备地址
     * @param reg_addr 寄存器地址
     * @param data 数据向量
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t writeRegister(uint16_t device_address, uint8_t reg_addr, const std::vector<uint8_t>& data, int timeout_ms = 1000);
    
    /**
     * @brief 使用设备句柄写寄存器（单字节，性能优化版本）
     * @param dev_handle 设备句柄
     * @param reg_addr 寄存器地址
     * @param data 数据
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t writeRegister(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr, uint8_t data, int timeout_ms = 1000);
    
    /**
     * @brief 读寄存器（单字节）
     * @param device_address 设备地址
     * @param reg_addr 寄存器地址
     * @param data 输出数据
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t readRegister(uint16_t device_address, uint8_t reg_addr, uint8_t& data, int timeout_ms = 1000);
    
    /**
     * @brief 读寄存器（多字节）
     * @param device_address 设备地址
     * @param reg_addr 寄存器地址
     * @param data 输出数据向量
     * @param size 读取大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t readRegister(uint16_t device_address, uint8_t reg_addr, std::vector<uint8_t>& data, size_t size, int timeout_ms = 1000);
    
    /**
     * @brief 使用设备句柄读寄存器（单字节，性能优化版本）
     * @param dev_handle 设备句柄
     * @param reg_addr 寄存器地址
     * @param data 输出数据
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t readRegister(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr, uint8_t& data, int timeout_ms = 1000);
    
    /**
     * @brief 使用设备句柄读寄存器（多字节，性能优化版本）
     * @param dev_handle 设备句柄
     * @param reg_addr 寄存器地址
     * @param buffer 输出缓冲区
     * @param size 读取大小
     * @param timeout_ms 超时时间(毫秒)
     * @return 错误码，ESP_OK表示成功
     */
    esp_err_t readRegister(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr, uint8_t* buffer, size_t size, int timeout_ms = 1000);
    
    // ==================== 工具函数 ====================
    
    /**
     * @brief 将esp_err_t转换为字符串
     * @param err 错误码
     * @return 错误描述字符串
     */
    static const char* errorToString(esp_err_t err);
    
    /**
     * @brief 检查设备地址是否有效
     * @param address 设备地址
     * @param addr_len 地址长度
     * @return true: 有效, false: 无效
     */
    static bool isValidDeviceAddress(uint16_t address, I2CAddrLength addr_len);

private:
    I2CType type_ = I2CType::HARDWARE;
    int port_ = -1;
    gpio_num_t scl_io_ = GPIO_NUM_NC;
    gpio_num_t sda_io_ = GPIO_NUM_NC;
    bool initialized_ = false;
    mutable std::mutex mutex_;
    
    // 硬件/软件I2C句柄
    i2c_master_bus_handle_t hw_bus_handle_;
    soft_i2c_master_bus_t sw_bus_handle_;
    
    // 设备管理
    std::unordered_map<uint16_t, i2c_master_dev_handle_t> device_handles_;
    
    // 内部方法
    esp_err_t initializeHardwareI2C(const I2CConfig& config);
    esp_err_t initializeSoftwareI2C(const I2CConfig& config);
    void cleanup();
    void cleanupInternal();  // 内部清理函数，调用前必须已持有锁
    
    // 内部传输方法
    esp_err_t internalTransmit(uint16_t device_address, const uint8_t* data, size_t size, int timeout_ms);
    esp_err_t internalReceive(uint16_t device_address, uint8_t* buffer, size_t size, int timeout_ms);
    esp_err_t internalTransmitReceive(uint16_t device_address, const uint8_t* write_data, size_t write_size,
                                     uint8_t* read_buffer, size_t read_size, int timeout_ms);
    
    // 设备句柄获取或创建
    i2c_master_dev_handle_t getOrCreateDeviceHandle(uint16_t device_address, uint32_t scl_speed_hz = 100000);
    
    // 内部创建设备函数（调用前必须已持有锁）
    i2c_master_dev_handle_t createDeviceInternal(uint16_t device_address, uint32_t scl_speed_hz);

    // 软件I2C内部实现
    esp_err_t softI2CStart();
    esp_err_t softI2CStop();
    esp_err_t softI2CWriteByte(uint8_t data);
    uint8_t softI2CReadByte(bool ack);
    void softI2CDelay();
    void softI2CSetSCL(bool level);
    void softI2CSetSDA(bool level);
    bool softI2CGetSDA();
}; 